package com.test.webflux.utils;

import com.fasterxml.jackson.annotation.JsonAutoDetect.Visibility;
import com.fasterxml.jackson.annotation.PropertyAccessor;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.*;
import com.fasterxml.jackson.databind.node.ObjectNode;
import com.fasterxml.jackson.datatype.jdk8.Jdk8Module;
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
import com.fasterxml.jackson.datatype.jsr310.deser.LocalDateDeserializer;
import com.fasterxml.jackson.datatype.jsr310.deser.LocalDateTimeDeserializer;
import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateSerializer;
import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateTimeSerializer;
import com.fasterxml.jackson.module.paramnames.ParameterNamesModule;
import lombok.extern.slf4j.Slf4j;

import java.io.IOException;
import java.text.SimpleDateFormat;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;

/**
 * 采用Jackson实现的json工具类
 * <p>
 * 对于要序列化/反序列化的目标对象，如果其有继承抽象类，或实现接口，则请使用 DeepCloneUtils 工具
 * </p>
 *
 * @author lm
 */
@Slf4j
public final class JacksonUtils {

    public static final ObjectMapper MAPPER = new ObjectMapper();
    /**
     * 默认时间格式
     */
    public static final String DEFAULT_DATE_FORMAT = "yyyy-MM-dd";
    public static final String DEFAULT_DATETIME_FORMAT = "yyyy-MM-dd HH:mm:ss.SSS";
    public static final String DEFAULT_DATETIME_FORMAT_SIMPLE = "yyyy-MM-dd HH:mm:ss";

    static {
        //ObjectMapper忽略未知字段
        MAPPER.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
        MAPPER.setVisibility(PropertyAccessor.FIELD, Visibility.ANY);
        // 默认的Date转换格式
        MAPPER.setDateFormat(new SimpleDateFormat(DEFAULT_DATETIME_FORMAT));
        MAPPER.disable(SerializationFeature.FAIL_ON_EMPTY_BEANS);
        // 对JDK8数据类型的支持
        JavaTimeModule javaTimeModule = new JavaTimeModule();
        javaTimeModule.addSerializer(LocalDate.class, new LocalDateSerializer(DateTimeFormatter.ofPattern(DEFAULT_DATE_FORMAT)));
        javaTimeModule.addDeserializer(LocalDate.class, new LocalDateDeserializer(DateTimeFormatter.ofPattern(DEFAULT_DATE_FORMAT)));
        javaTimeModule.addSerializer(LocalDateTime.class, new LocalDateTimeSerializer(DateTimeFormatter.ofPattern(DEFAULT_DATETIME_FORMAT_SIMPLE)));
        javaTimeModule.addDeserializer(LocalDateTime.class, new LocalDateTimeDeserializer(DateTimeFormatter.ofPattern(DEFAULT_DATETIME_FORMAT_SIMPLE)));
        MAPPER.registerModule(javaTimeModule);
        MAPPER.registerModule(new ParameterNamesModule());
        MAPPER.registerModule(new Jdk8Module());
    }

    /**
     * 将目标对象序列化为字节流
     */
    public static byte[] toJSONBytes(Object object) throws IOException {
        if (Objects.isNull(object)) {
            return null;
        }
        try {
            MAPPER.setPropertyNamingStrategy(PropertyNamingStrategy.LOWER_CAMEL_CASE);
            byte[] byteArr = MAPPER.writeValueAsBytes(object);
            return byteArr;
        } catch (JsonProcessingException e) {
            throw new IOException(e);
        }
    }

    /**
     * 将目标对象序列化为字符串
     */
    public static String toJSONString(Object object) throws IOException {
        if (Objects.isNull(object)) {
            return null;
        }
        try {
            MAPPER.setPropertyNamingStrategy(PropertyNamingStrategy.LOWER_CAMEL_CASE);
            String strArr = MAPPER.writeValueAsString(object);
            return strArr;
        } catch (JsonProcessingException e) {
            throw new IOException(e);
        }
    }



    /**
     * 将目标对象序列化为字符串
     */
    public static String toJSONStringNotThrow(Object object) {
        if (Objects.isNull(object)) {
            return null;
        }
        try {
            MAPPER.setPropertyNamingStrategy(PropertyNamingStrategy.LOWER_CAMEL_CASE);
            String strArr = MAPPER.writeValueAsString(object);
            return strArr;
        } catch (JsonProcessingException e) {
            log.error("json转换异常，详细信息：" , e);
        }
        return null;
    }

    /**
     * 将目标对象 ObjectNode
     */
    public static ObjectNode toJSONObjectNode(Object object) throws IOException {
        if (Objects.isNull(object)) {
            return null;
        }
        MAPPER.setPropertyNamingStrategy(PropertyNamingStrategy.LOWER_CAMEL_CASE);
        ObjectNode objectNode = MAPPER.valueToTree(object);
        return objectNode;
    }


    /**
     * 从字节流反序列化，得到目标类型的对象
     */
    public static <T> T fromJSONBytes(byte[] arg0, Class<T> arg1) throws IOException {
        MAPPER.setPropertyNamingStrategy(PropertyNamingStrategy.LOWER_CAMEL_CASE);
        T obj = MAPPER.readValue(arg0, arg1);
        return obj;
    }

    /**
     * 从字节流反序列化，得到目标类型的对象
     */
    public static <T> T fromJSONBytes(byte[] arg0, TypeReference<T> arg1) throws IOException {
        MAPPER.setPropertyNamingStrategy(PropertyNamingStrategy.LOWER_CAMEL_CASE);
        T obj = MAPPER.readValue(arg0, arg1);
        return obj;
    }

    /**
     * 从字符串反序列化，得到目标类型的对象
     */
    public static <T> T fromJSONString(String arg0, Class<T> arg1) throws IOException {
        MAPPER.setPropertyNamingStrategy(PropertyNamingStrategy.LOWER_CAMEL_CASE);
        T obj = MAPPER.readValue(arg0, arg1);
        return obj;
    }

    /**
     * 从字符串反序列化，得到目标类型的对象
     */
    public static <T> T fromJSONString(String arg0, JavaType javaType) throws IOException {
        MAPPER.setPropertyNamingStrategy(PropertyNamingStrategy.LOWER_CAMEL_CASE);
        T obj = MAPPER.readValue(arg0, javaType);
        return obj;
    }

    /**
     * 从字符串反序列化，得到目标类型的对象
     */
    public static <T> T fromJSONString(String arg0, TypeReference<T> arg1) throws IOException {
        MAPPER.setPropertyNamingStrategy(PropertyNamingStrategy.LOWER_CAMEL_CASE);
        T obj = MAPPER.readValue(arg0, arg1);
        return obj;
    }


    /**
     * 从字符串反序列化，得到目标类型的对象List
     */
    public static <T> List<T> fromJSONStringToList(String arg0, Class<T> arg1) throws IOException {
        MAPPER.setPropertyNamingStrategy(PropertyNamingStrategy.LOWER_CAMEL_CASE);
        JavaType jt = MAPPER.getTypeFactory().constructParametricType(ArrayList.class, arg1);
        List<T> obj = MAPPER.readValue(arg0, jt);
        return obj;
    }

    /**
     *
     * @param fromValue
     * @param toValueType
     * @return
     * @param <T>
     * @throws IllegalArgumentException
     */
    public static  <T> T convertValue(Object fromValue, Class<T> toValueType) throws IllegalArgumentException {
        return MAPPER.convertValue(fromValue, toValueType);
    }
}
